package com.wx.task.checkbill;

import cn.hutool.core.bean.BeanUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 对账 version : 3.0
 * 需求：
 * 1. 查询订单库 -- 寻找未对账的订单  getOrders
 * 2. 查询派送库 -- 寻找派送信息     getDOrders
 * 3. 检查两方信息                 check
 * 4. 有差异的数据，存入差异库中      saveDiff
 *
 * @author wang.xun
 * @date 2023/07/31
 */
@Slf4j
public class CheckBillV3 {

    final static List<Order> orders = Arrays.asList(new Order(1, 1), new Order(2, 1), new Order(3, 2));
    final static List<Order> dOrders = Arrays.asList(new Order(1, 1), new Order(2, 1), new Order(3, 1));
    final static List<Order> diffOrders = new ArrayList<>();


    public Order getOrders(int index) {

        return orders.get(index);
    }


    public Order getDOrders(int index) {

        return dOrders.get(index);
    }

    public boolean check(Order order, Order Dorder) {

        return order.equals(Dorder);
    }

    public void save(Order order) {
        diffOrders.add(order);
    }

    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    static class Order {
        private int orderId;
        private int status;

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            Order order = (Order) o;
            return orderId == order.orderId && status == order.status;
        }

        @Override
        public int hashCode() {
            return Objects.hash(orderId, status);
        }
    }


    /**
     * v2.0 版本
     * 将不需要依赖的 获取订单信息 获取物流信息 并行执行
     * 因为check 需要依赖订单信息 物流信息 所以让主线程阻塞在t1 t2 上，等待 t1 t2 执行完，在进行check检查
     * 此处每次循环都要新建线程，导致消耗资源
     * v3.0 版本
     * 利用线程池，池化线程，防止线程创建销毁浪费资源
     * 利用
     *
     * @param args arg游戏
     */
    public static void main(String[] args) {

        ExecutorService pool = Executors.newFixedThreadPool(2);




        CheckBillV3 bill = new CheckBillV3();
        for (int i = 0; i < 3; i++) {
            CountDownLatch countDownLatch = new CountDownLatch(2);
            final int index = i;
            Order order = new Order();

            pool.execute(() -> {
                Order temp = bill.getOrders(index);
                BeanUtil.copyProperties(temp, order);
                countDownLatch.countDown();
            });
            Order dOrder = new Order();
            pool.execute(() -> {
                Order temp = bill.getDOrders(index);
                BeanUtil.copyProperties(temp, dOrder);
                countDownLatch.countDown();
            });


            try {
                // 等待门闩，t1 t2 执行完之后就会放行
                countDownLatch.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (!bill.check(order, dOrder)) {
                bill.save(order);
            }
        }
        diffOrders.forEach(order -> log.info("对账后，差异化的数据 :{}", order));
        // 关闭线程池
        pool.shutdown();
    }
}
